package com.louis.scheduler.support;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.louis.mail.MailSender;
import com.louis.util.JodaUtil;

import javax.mail.MessagingException;
import java.util.Date;


/**
 * @author Lijun jiang
 * @Date: May 10, 2011
 * @Time: 1:23:18 PM
 */

@Configurable(autowire = Autowire.BY_NAME, dependencyCheck = false)
public abstract class AbstractJobDetailAndTrigger implements JobDetailAndTrigger {

    private JobDetail jobDetail;
    protected PlatformTransactionManager transactionManager;
    protected MailSender mailSender;
    private int repeatIntervalMinute = 1;
    private int repeatCount = 3;
    protected final Log logger = LogFactory.getLog(this.getClass());


    public AbstractJobDetailAndTrigger() {
    }

    public AbstractJobDetailAndTrigger(String jobName, String groupName) {
        initJobDetail(jobName, groupName);
    }

    protected void initJobDetail(String jobName, String groupName) {
        jobDetail = new JobDetail();
        jobDetail.setName(jobName);
        jobDetail.setGroup(groupName);
        jobDetail.setJobClass(this.getClass());
    }

    public void addToJobDataMap(Object key, Object value) {
        getJobDetail().getJobDataMap().put(key, value);
    }

    public JobDetail getJobDetail() {
        if (jobDetail == null) {
            initJobDetail(getClass().getName(), System.nanoTime() + "");
        }
        return jobDetail;
    }

    public Trigger getTrigger() {
        return new SimpleTrigger(getJobDetail().getName(), getJobDetail().getGroup(), getExecuteDate());
    }

    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);
        try {
            doExecute(jobExecutionContext);
            transactionManager.commit(status);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(status);
        } finally {
            JobDetail jobDetail1 = jobExecutionContext.getJobDetail();
            try {
                DynamicScheduler.unSchedule(jobDetail1.getName(), jobDetail1.getGroup());
            } catch (SchedulerException e) {
                e.printStackTrace();
                logger.error(e);
            }
        }
    }

    public void retry(JobExecutionContext context) throws SchedulerException, MessagingException {
        Object obj = context.getJobDetail().getJobDataMap().get("executeCount");
        int executeCount = 1;
        if (obj != null) {
            executeCount = Integer.parseInt(obj.toString());
        }
        JobDetail jobDetail = context.getJobDetail();
        Trigger trigger = context.getTrigger();
        if (executeCount <= getRepeatCount()) {
            Date DateTime = JodaUtil.now().plusMinutes(getRepeatIntervalMinute()).toDate();
            trigger.setStartTime(DateTime);
            jobDetail.getJobDataMap().put("executeCount", executeCount + 1);
            DynamicScheduler.unSchedule(jobDetail.getName(), jobDetail.getGroup());
            DynamicScheduler.schedule(jobDetail, trigger);
        } else {
            resolveFinal(context);
        }
    }

    protected void resolveFinal(JobExecutionContext context) throws MessagingException {
//        JobDetail jobDetail = context.getJobDetail();
//        mailSender.send("dynamicScheduler exception", "jobName=" + jobDetail.getName() + "\tgroupName=" + jobDetail.getGroup(), false);
    }

    public abstract Date getExecuteDate();

    public abstract void doExecute(JobExecutionContext jobExecutionContext) throws Exception;


    public int getRepeatIntervalMinute() {
        return repeatIntervalMinute;
    }

    public void setRepeatIntervalMinute(int repeatIntervalMinute) {
        this.repeatIntervalMinute = repeatIntervalMinute;
    }

    public int getRepeatCount() {
        return repeatCount;
    }

    public void setRepeatCount(int repeatCount) {
        this.repeatCount = repeatCount;
    }

    @Autowired(required = true)
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    @Autowired(required = true)
    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

}